// 数据结构转换
import { isObject } from "./isTarget";
/**
 * 数组转树型结构
 * @param {any[]} array
 * @param {string} getId
 * @param {string} getParentID
 * @returns
 */
export function arrayToTree(array, getId = "id", getParentID = "parentID") {
  const map = array.reduce((acc, item) => {
    acc[item[getId]] = { ...item, children: [] };
    return acc;
  }, {});
  const tree = [];
  for (const item of array) {
    const parentKey = item[getParentID] ?? "0";
    const parent = map[parentKey];
    if (parent && parentKey !== item[getId]) {
      // 防止循环引用
      parent.children.push(map[item[getId]]);
    } else if (!parent) {
      tree.push(map[item[getId]]);
    }
  }
  return tree;
}

/**
 * 数组分组
 * @param {any[]} array
 * @param {string|(item:object)=>string} keySelector
 * @returns
 */
export function groupBy(array, keySelector) {
  const groups = {};
  if (typeof keySelector === "string") {
    keySelector = (item) => item[keySelector];
  }
  for (const item of array) {
    const groupName = keySelector(item);
    if (!groups[groupName]) {
      groups[groupName] = [];
    }
    groups[groupName].push(item);
  }
  return groups;
}

/**
 * 深度优先遍历(对象)
 * @param {object} node
 * @param {string} children
 * @param {(node)=>boolean} callback
 * @returns {boolean} 是否遍历完成
 */
export function dfsObject(node, callback, children = "children") {
  if (!node) return false;
  const res = callback(node);
  if (res) return false;
  if (!node[children]) return false;
  for (const child of node[children]) {
    dfs(child, children, callback);
  }
  return true;
}
/**
 * 深度优先遍历(数组)
 * @param {object} node
 * @param {string} children
 * @param {(node,parent,i)=>boolean} callback
 * @returns {boolean} 是否遍历完成
 */
export function dfsArray(array, callback, children = "children") {
  let parent = [];
  function dfs(array, callback, children) {
    for (let i = 0; i < array.length; i++) {
      const item = array[i];
      const res = callback(item, parent, i);
      if (res) {
        return false;
      }
      if (item[children]) {
        parent.push(item);
        dfs(item[children], callback, children, parent);
      }
    }
    return true;
  }
  return dfs(array, callback, children, parent);
}

/**
 * 从对象中安全地检索嵌套属性值
 * @param {Object} object 对象
 * @param {string|string[]} keys 键值
 * @example f({ a: 1, b: 2 }, "a") // 1
 * @example f({ a: 1, b: 2 }, ["a", "b"]) // [1, 2]
 * @example f({ a: {c:1}, b: {c:2} }, ["a.c", "b.c"]) // [1, 2]
 * @example f({ a: {b:2} }, "a.b") // 2
 */
export function getNestedValues(object, keys) {
  if (typeof keys === "string") {
    return keys.split(".").reduce((acc, key) => {
      if (acc && key in acc) {
        return acc[key];
      }
      return undefined;
    }, object);
  } else {
    const result = [];
    keys.forEach((key) => {
      result.push(getNestedValues(object, key));
    });
    return result;
  }
}

/**
 * 对象深度合并
 * @param {object} original
 * @param {object} object
 * @returns
 */
export function merge(original, object) {
  for (const key in object) {
    if (Object.prototype.hasOwnProperty.call(object, key)) {
      const srcValue = object[key];
      const originalValue = original[key];
      // 处理对象嵌套
      if (isObject(srcValue) && isObject(originalValue)) {
        merge(originalValue, srcValue);
      } else if (Array.isArray(srcValue) && Array.isArray(originalValue)) {
        // 处理数组合并
        original[key] = [...originalValue, ...srcValue];
      } else {
        original[key] = srcValue;
      }
    }
  }
  return original;
}

function omit(obj, keys) {
  return Object.keys(obj).reduce((acc, key) => {
    if (!keys.includes(key)) {
      acc[key] = obj[key];
    }
    return acc;
  }, {});
}
